#ifndef HOUGHSPACE_H
#define HOUGHSPACE_H

/**
 * \file HoughSpace.h
 * \brief Fichier contenant la déclaration de la classe HoughSpace.
 */

#include <vector>
#include <fstream>
#include "Circle.h"
#include "HoughFrame.h"
#include "Point.h"

#define RESOLUTION 0
#define SIZE 1

using namespace std;

class HoughSpace
{
        /* \class HoughSpace
         * \brief Cette classe représente un espace de hough pour les cercles sous la forme d'un tableau à trois dimensions (a,b,r).
         */
        private :
        
        Point bot;                                                      /*!<Point de coordonnées a, b et r minimum.*/
        Point top;                                                      /*!<Point de coordonnées a, b et r maximum.*/
                        
        int nbFrameA;                                           /*!<Nombre de cases selon a de la grille.*/
        int nbFrameB;                                           /*!<Nombre de cases selon b de la grille.*/
        int nbFrameR;                                           /*!<Nombre de cases selon r de la grille.*/
        
        float frameSizeA;                                       /*!<Taille d'une case de l'espace selon l'axe a.*/
        float frameSizeB;                                       /*!<Taille d'une case de l'espace selon l'axe b.*/
        float frameSizeR;                                       /*!<Taille d'une case de l'espace selon l'axe r.*/
        
        float aFrameMax;                                        /*!<a de la case de plus haut score de l'espace.*/
        float bFrameMax;                                        /*!<b de la case de plus haut score de l'espace.*/
        float rFrameMax;                                        /*!<r de la case de plus haut score de l'espace.*/
        
        int scoreMax;                                           /*!<score de la case de plus haut score de l'espace.*/
        int scoreTotal;                                         /*!<score total de l'espace.*/
        
        HoughFrame*** frames;                           /*!<Tableau trois dimensions de cases de Hough.*/
        
        public :
        
        /*!
         *  \brief Constructeur de la classe HoughSpace
         *
         *  Constructeur de la classe HoughSpace, tous les attributs sont initialisés à 0 et à NULL.
         *
         */
        HoughSpace();
                        
        /*!
         *  \brief Constructeur de la classe HoughSpace
         *
         *  Constructeur de la classe HoughSpace
         *
         *  \param _mode : mode de création de l'espace : si _mode vaut RESOLUTION, _a _b et _r représenteront le nombre de cases de l'espace dans ces axes. S'il vaut SIZE alors ils définissent la taille des cases selon chaque axe.
         *  \param _bot : Coin inferieur gauche de l'espace.
         *  \param _top : Coin superieur droit de l'espace.
         *  \param _a : définit, selon le mode, la taille d'une case de l'espace selon l'axe a, ou le nombre de case sur cet axe.
         *  \param _b : définit, selon le mode, la taille d'une case de l'espace selon l'axe b, ou le nombre de case sur cet axe.
         *  \param _r : définit, selon le mode, la taille d'une case de l'espace selon l'axe r, ou le nombre de case sur cet axe.
         */
        HoughSpace(int _mode, Point _bot, Point _top, float _a, float _b, float _r);
        
        /*!
         *  \brief Destructeur de HoughSpace.
         *
         *  Destructeur de HoughSpace.
         *
         */
        ~HoughSpace();
        
        /*!
         *  \brief Initialise un espace de Hough non encore initialisé (son attribut frames est encore NULL).
         *
         *  Agit de la même manière que le constructeur de la classe HoughSpace
         *
         *  \param _mode : mode de création de l'espace : si _mode vaut RESOLUTION, _a _b et _r représenteront le nombre de cases de l'espace dans ces axes. S'il vaut SIZE alors ils définissent la taille des cases selon chaque axe.
         *  \param _bot : Coin inferieur gauche de l'espace.
         *  \param _top : Coin superieur droit de l'espace.
         *  \param _a : définit, selon le mode, la taille d'une case de l'espace selon l'axe a, ou le nombre de case sur cet axe.
         *  \param _b : définit, selon le mode, la taille d'une case de l'espace selon l'axe b, ou le nombre de case sur cet axe.
         *  \param _r : définit, selon le mode, la taille d'une case de l'espace selon l'axe r, ou le nombre de case sur cet axe.
         *
         *  \retun : void
         */
        void init(int _mode, Point _bot, Point _top, float _a, float _b, float _r);

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à nbFrameA
         *
         * \return : Renvoie le nombre de cases selon A.
         */
        inline int getNbFrameA() { return this->nbFrameA; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à nbFrameB
         *
         * \return : Renvoie le nombre de cases selon B.
         */
        inline int getNbFrameB() { return this->nbFrameB; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à nbFrameR
         *
         * \return : Renvoie le nombre de cases selon R.
         */
        inline int getNbFrameR() { return this->nbFrameR; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à frameSizeA
         *
         * \return : Renvoie la taille des cases de l'espace de Hough selon A.
         */
        inline float getFrameSizeA() { return this->frameSizeA; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à frameSizeB
         *
         * \return : Renvoie la taille des cases de l'espace de Hough selon B.
         */
        inline float getFrameSizeB() { return this->frameSizeB; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à frameSizeR
         *
         * \return : Renvoie la taille des cases de l'espace de Hough selon R.
         */
        inline float getFrameSizeR() { return this->frameSizeR; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à aFrameMax
         *
         * \return : Renvoie la valeur de a pour la case de score maximum.
         */
        inline float getAFrameMax() { return this->aFrameMax; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à bFrameMax
         *
         * \return : Renvoie la valeur de b pour la case de score maximum.
         */
        inline float getBFrameMax() { return this->bFrameMax; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à rFrameMax
         *
         * \return : Renvoie la valeur de r pour la case de score maximum.
         */
        inline float getRFrameMax() { return this->rFrameMax; }   

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à bot
         *
         * \return : Renvoie le point bot.
         */
        inline Point getBot() { return this->bot; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à top
         *
         * \return : Renvoie le point top.
         */
        inline Point getTop() { return this->top; }

        /*!
         *  \brief Accesseur de la classe Hough
         *
         *  Accède à scoreMax
         *
         * \return : Renvoie le score de la case de score maximum.
         */
        inline int getScoreMax() { return this->scoreMax; }      

        /*!
         *  \brief Renvoie la valeur de la case de coorconnées (a,b,r)
         *
         *  Renvoie la valeur de la case de coorconnées (a,b,r)
         *
         * \param _a : Coordonnée a.
         * \param _b : Coordonnée b.
         * \param _r : Coordonnée r.
         *
         * \return : Valeur de la case.
         */
        inline int getScore(int _a, int _b, int _r) { return this->frames[_a][_b][_r].getScore(); }

        /*!
         *  \brief Renvoie la valeur de scoreTotal
         *
         *  Renvoie la valeur du nombre total de points de l'espace de Hough
         *
         * \return : Valeur de scoreTotal.
         */
        inline int getScoreTotal() { return this->scoreTotal; }

        /*!
         *  \brief Renvoie une copie de la case de coorconnées (a,b,r)
         *
         *  Renvoie une copie de la case de coorconnées (a,b,r)
         *
         * \param _a : Coordonnée _a.
         * \param _b : Coordonnée _b.
         * \param _r : Coordonnée _r.
         *
         * \return : Copie de la case.
         */
        inline HoughFrame getHoughFrame(int _a, int _b, int _r) { return this->frames[_a][_b][_r]; }

        /*!
         *  \brief Modificateur de la classe HoughSpace
         *
         *  Modifie la valeur de aFrameMax.
         *
         * \param _aFrameMax : Nouvelle valeur de aFrameMax.
         *
         * \return : vod
         */
        inline void setAFrameMax(float _aFrameMax) { this->aFrameMax = _aFrameMax; }

        /*!
         *  \brief Modificateur de la classe HoughSpace
         *
         *  Modifie la valeur de bFrameMax.
         *
         * \param _bFrameMax : Nouvelle valeur de bFrameMax.
         *
         * \return : void
         */
        inline void setBFrameMax(float _bFrameMax) { this->bFrameMax = _bFrameMax; }

        /*!
         *  \brief Modificateur de la classe HoughSpace
         *
         *  Modifie la valeur de rFrameMax.
         *
         * \param _rFrameMax : Nouvelle valeur de rFrameMax.
         *
         * \return : void
         */
        inline void setRFrameMax(float _rFrameMax) { this->rFrameMax = _rFrameMax; }
        
        /*!
         *  \brief Modificateur de la classe HoughSpace
         *
         *  Modifie le score de scoreMax.
         *
         * \param _scoreMax : Nouvelle valeur de scoreMax.
         *
         * \return : void
         */
        inline void setScoreMax(int _scoreMax) { this->scoreMax = _scoreMax; }
        
        /*!
         *  \brief Remplit l'espace de Hough
         *
         *  Remplit l'espace de Hough à partir d'un ensemble de cercles.
         *
         * \param _tabCircles : vector de cercles.
         *
         * \return : void
         */
        void fill(vector <Circle> _tabCircles);
        
        /*!
         *  \brief Méthode permettant d'ajouter à un tableau les cercles significatifs dans un espace de Hough.
         *
         *  Méthode qui ajoute à un tableau les cercles significatifs d'un espace de Hough - i.e. les cercles représentés par des cases de score supérieur à un sueil.
         *
         *  \param _rslt : Tableau de cercle auquel on ajoute les cercles significatifs trouvés.
         *  \param _thresh : seuil au delà duquel le score d'une case de l'espace devient représentatif.
         *
         *  \return : void
         */
        void threshold(vector <Circle> &_rslt, int _thresh);

        /*!
         *  \brief Méthode permettant de récupérer les cercles significatifs dans l'espace de Hough.
         *
         *  Méthode qui récupère les cercles significatifs de l'espace de Hough - i.e. les cercles représentés par des cases de score supérieur à un sueil.
         *
         *  \param _thresh : seuil au delà duquel le score d'une case de l'espace devient représentatif.
         *
         *  \return : Renvoie un vecteur de cercle contenant tous les cercles représentatifs situés dans cet espace.
         */
        vector<Circle> threshold ( int _thresh );

        /*!
         *  \brief Méthode permettant de récupérer les cercles significatifs dans l'espace de Hough.
         *
         *  Méthode qui récupère les cercles significatifs de l'espace de Hough - i.e. les cercles représentés par des cases de score supérieur à un sueil.
         *      Cette méthode utilise un seuil variable, en fonction du nombre de points dans l'esapce de Hough.
         *      Plus le nombre de points est important, plus le seuil sera haut, et inversement. 
         *
         *  \param _thresh1 : seuil minimum au delà duquel le score d'une case de l'espace devient représentatif.
         *  \param _thresh2 : seuil maximum au delà duquel le score d'une case de l'espace devient représentatif.
         *
         *  \return : Renvoie un vecteur de cercle contenant tous les cercles représentatifs situés dans cet espace.
         */
        vector<Circle> threshold(float _thresh1, float _thresh2);
        
        /*!
         *  \brief Méthode permettant d'incrémenter la valeur d'une case de l'espace de Hough.
         *
         *  Méthode permettant d'incrémenter la valeur de la case de l'espace de Hough de coordonnées (a,b,r).
         *
         *  \param _a : coordonnée a de la case à incrémenter.
         *  \param _b : coordonnée b de la case à incrémenter.
         *  \param _r : coordonnée r de la case à incrémenter.
         *
         *  \return : void
         */
        void increment ( int _a, int _b, int _r );

        /*!
         *  \brief Méthode permettant d'incrémenter la valeur d'une case de l'espace de Hough.
         *
         *  Méthode permettant d'incrémenter plusieurs fois la valeur de la case de l'espace de Hough de coordonnées (a,b,r).
         *
         *  \param _a : coordonnée a de la case à incrémenter.
         *  \param _b : coordonnée b de la case à incrémenter.
         *  \param _r : coordonnée r de la case à incrémenter.
         *  \param _val : nombre d'incrémentations.
         *
         *  \return : void
         */
        void increment ( int _a, int _b, int _r , int _val);
		
		/* Ajoute un cercle dans l'espace de Hough */
		void addCircle ( Circle _c );
		
		/* Fonction pour écrire les cercles d'un vecteur de cercles dans un fichier sous forme :
		   a b r
		   a b r
		   ...
		*/
		static void saveCircles( vector<Circle> _circles, const QString& _fileName );
};
#endif
